// entry-server.js
import { createApp } from './app'

const isDev = process.env.NODE_ENV !== 'production' // 开发模式 || 生产模式

export default context => {
  const s = isDev && Date.now()

  // 由于有可能会是异步路由钩子函数或组件，因此咱们将返回一个 Promise，
  // 以便服务器可以等待全部的内容在渲染前就已经准备就绪。
  return new Promise((resolve, reject) => {
    const { app, router, store } = createApp()
    // push对应访问路径
    router.push(context.url)
    // 等到 router 将可能的异步组件和钩子函数解析完
    router.onReady(() => {
      const matchedComponents = router.getMatchedComponents() // 返回当前路径匹配到的组件
      // 匹配不到的路由，reject()，返回 404
      if (!matchedComponents.length) {
        reject({ code: 404 })
      }

      // Promise.all 组件的 asyncData 方法 拿数据 全部数据返回后 为window.__INITIAL_STATE__赋值并 resolve(app)
      Promise.all(
        matchedComponents.map(component => {
          // 调用组件asyncData方法 传入store与当前路由信息
          let pm =
            component.asyncData &&
            component.asyncData(store, router.currentRoute, context)

          if (!context.asyncDataCache && component.asyncDataCache) {
            context.asyncDataCache = component.asyncDataCache
          }
          return pm
        })
      )
        .then(() => {
          //js-ignore
          isDev && console.log(`data pre-fetch: ${Date.now() - s}ms`)
          // 为window.__INITIAL_STATE__ 赋值 (可理解为window.__INITIAL_STATE__ = store.state)
          // 将服务端获取的数据注入到前端
          // 需要一直使用加密状态，因为页面会缓存
          // 将state下professionData加密即可
          // 当前app是vue实例对象，encodeString是绑定实例上的方法
          store.state.professionData = app.encodeString(process.professionData)
          store.state.originalUrl = context.originalUrl
          store.state.globalConfig = context.globalConfig

          //此处需要context.state需要赋值store.state,如果context_state 和store.state不同会造成页面组件数据渲染三次，因为会发生两次变化
          context.state = store.state

          resolve(app)
        })
        .catch(reject)
    })
  })
}
